home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / umddvi / dvi / dviselect.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  22KB  |  975 lines

  1. /*
  2.  * Copyright (c) 1987 University of Maryland Department of Computer Science.
  3.  * All rights reserved.  Permission to copy for any purpose is hereby granted
  4.  * so long as this copyright notice remains intact.
  5.  */
  6.  
  7. #ifndef lint
  8. static char rcsid[] = "$Header: dviselect.c,v 2.6 87/06/16 17:19:24 chris Exp $";
  9. #endif
  10.  
  11. /*
  12.  * DVI page selection program
  13.  *
  14.  * Reads DVI version 2 files and selects pages, writing a new DVI
  15.  * file.  The new DVI file is technically correct, though we do not
  16.  * adjust the tallest and widest page values, nor the DVI stack size.
  17.  * This is all right since the values will never become too small,
  18.  * but it might be nice to fix them up.  Perhaps someday . . . .
  19.  */
  20.  
  21. #include "types.h"
  22. #include "dvi.h"
  23. #include "dviclass.h"
  24. #include "dvicodes.h"
  25. #include "fio.h"
  26. #include "search.h"
  27. #include <stdio.h>
  28. #include <ctype.h>
  29.  
  30. char  *ProgName;
  31. extern int   errno;
  32. extern char *optarg;
  33. extern int   optind;
  34.  
  35. /* Globals */
  36. char    serrbuf[BUFSIZ];    /* buffer for stderr */
  37.  
  38. /*
  39.  * We will try to keep output lines shorter than MAXCOL characters.
  40.  */
  41. #define MAXCOL    75
  42.  
  43. /*
  44.  * We use the following structure to keep track of fonts we have seen.
  45.  * The final DVI file lists only the fonts it uses.
  46.  */
  47. struct fontinfo {
  48.     i32    fi_newindex;    /* font number in output file */
  49.     int    fi_reallyused;    /* true => used on a page we copied */
  50.     i32    fi_checksum;    /* the checksum */
  51.     i32    fi_mag;        /* the magnification */
  52.     i32    fi_designsize;    /* the design size */
  53.     short    fi_n1;        /* the name header length */
  54.     short    fi_n2;        /* the name body length */
  55.     char    *fi_name;    /* the name itself */
  56. };
  57.  
  58. /*
  59.  * We need to remember which pages the user would like.  We build a linked
  60.  * list that allows us to decide (for any given page) whether it should
  61.  * be included in the output file.  Each page has ten \count variables
  62.  * associated with it.  We put a bound on the values allowed for each, and
  63.  * keep a linked list of alternatives should any be outside the allowed
  64.  * range.  For example, `dviselect *.3,10-15' would generate a two-element
  65.  * page list, with the first allowing any value for \count0 (and \counts 2 to
  66.  * 9) but \count1 restricted to the range 3-3, and the second restricting
  67.  * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
  68.  *
  69.  * In case no bound is specified, the `nol' or `noh' flag is set (so that
  70.  * we need not fix some `large' number as a maximum value).
  71.  *
  72.  * We also allow `absolute' page references, where the first page is
  73.  * page 1, the second 2, and so forth.  These are specified with an
  74.  * equal sign: `dviselect =4:10' picks up the fourth through tenth
  75.  * sequential pages, irrespective of \count values.
  76.  */
  77. struct pagesel {
  78.     i32    ps_low;        /* lower bound */
  79.     int    ps_nol;        /* true iff no lower bound */
  80.     i32    ps_high;    /* upper bound */
  81.     int    ps_noh;        /* true iff no upper bound */
  82. };
  83. struct pagelist {
  84.     struct    pagelist *pl_alt;    /* next in a series of alternates */
  85.     int    pl_len;            /* number of ranges to check */
  86.     int    pl_abs;            /* true iff absolute page ref */
  87.     struct    pagesel pl_pages[10];    /* one for each \count variable */
  88. };
  89.  
  90. int    SFlag;            /* true => -s, silent operation */
  91.  
  92. struct    search *FontFinder;    /* maps from input indicies to fontinfo */
  93. i32    NextOutputFontIndex;    /* generates output indicies */
  94. i32    CurrentFontIndex;    /* current (old) index in input */
  95. i32    OutputFontIndex;    /* current (new) index in ouput */
  96.  
  97. struct    pagelist *PageList;    /* the list of allowed pages */
  98.  
  99. FILE    *inf;            /* the input DVI file */
  100. FILE    *outf;            /* the output DVI file */
  101.  
  102. int    ExpectBOP;        /* true => BOP ok */
  103. int    ExpectEOP;        /* true => EOP ok */
  104.  
  105. long    StartOfLastPage;    /* The file position just before we started
  106.                    the last page (this is later written to
  107.                    the output file as the previous page
  108.                    pointer). */
  109. long    CurrentPosition;    /* The current position of the file */
  110.  
  111. int    UseThisPage;        /* true => current page is selected */
  112.  
  113. i32    InputPageNumber;    /* current absolute page in old DVI file */
  114. int    NumberOfOutputPages;    /* number of pages in new DVI file */
  115.  
  116. i32    Numerator;        /* numerator from DVI file */
  117. i32    Denominator;        /* denominator from DVI file */
  118. i32    DVIMag;            /* magnification from DVI file */
  119.  
  120. i32    Count[10];        /* the 10 \count variables */
  121.  
  122. /* save some string space: we use this a lot */
  123. char    writeerr[] = "error writing DVI file";
  124.  
  125. char    *malloc(), *realloc(), *sprintf();
  126.  
  127. /*
  128.  * lint gets rather confused with the current definitions of getc and putc,
  129.  * so we redefine them here (#if lint).  This should really be in the
  130.  * standard I/O library, but I am not about to go change it now!
  131.  */
  132. #ifdef lint
  133. #undef putc
  134. #undef getc
  135. #define putc(c,f) (*(f)->_ptr++ = (unsigned) (c))
  136. #define getc(f)   (*(f)->_ptr++)
  137. #endif
  138.  
  139. /*
  140.  * Return true iff the 10 \counts are one of the desired output pages.
  141.  */
  142. DesiredPageP()
  143. {
  144.     register struct pagelist *pl;
  145.  
  146.     for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
  147.         register struct pagesel *ps = pl->pl_pages;
  148.         register int i;
  149.         register i32 *pagep;
  150.  
  151.         pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
  152.         for (i = 0; i < pl->pl_len; i++, ps++, pagep++)
  153.             if (!ps->ps_nol && *pagep < ps->ps_low ||
  154.                 !ps->ps_noh && *pagep > ps->ps_high)
  155.                 break;    /* not within bounds */
  156.         if (i >= pl->pl_len)
  157.             return (1);    /* success */
  158.     }
  159.     return (0);
  160. }
  161.  
  162. /*
  163.  * Print a message to stderr, with an optional leading space, and handling
  164.  * long line wraps.
  165.  */
  166. message(space, str, len)
  167.     int space;
  168.     register char *str;
  169.     register int len;
  170. {
  171.     static int beenhere;
  172.     static int col;
  173.  
  174.     if (!beenhere)
  175.         space = 0, beenhere++;
  176.     if (len == 0)
  177.         len = strlen(str);
  178.     col += len;
  179.     if (space) {
  180.         if (col >= MAXCOL)
  181.             (void) putc('\n', stderr), col = len;
  182.         else
  183.             (void) putc(' ', stderr), col++;
  184.     }
  185.     while (--len >= 0)
  186.         (void) putc(*str++, stderr);
  187.     (void) fflush(stderr);
  188. }
  189.  
  190. /*
  191.  * Start a page (process a DVI_BOP).
  192.  */
  193. BeginPage()
  194. {
  195.     register i32 *i;
  196.  
  197.     if (!ExpectBOP)
  198.         GripeUnexpectedOp("BOP");
  199.     ExpectBOP = 0;
  200.     ExpectEOP++;        /* set the new "expect" state */
  201.  
  202.     OutputFontIndex = -1;    /* new page requires respecifying font */
  203.     InputPageNumber++;    /* count it */
  204.     for (i = Count; i < &Count[10]; i++)
  205.         fGetLong(inf, *i);
  206.     (void) GetLong(inf);    /* previous page pointer */
  207.  
  208.     if ((UseThisPage = DesiredPageP()) == 0)
  209.         return;
  210.  
  211.     (void) putc(DVI_BOP, outf);
  212.     for (i = Count; i < &Count[10]; i++)
  213.         PutLong(outf, *i);
  214.     PutLong(outf, StartOfLastPage);
  215.     if (ferror(outf))
  216.         error(1, errno, writeerr);
  217.  
  218.     StartOfLastPage = CurrentPosition;
  219.     CurrentPosition += 45;    /* we just wrote this much */
  220.  
  221.     if (!SFlag) {        /* write nice page usage messages */
  222.         register int z = 0;
  223.         register int mlen = 0;
  224.         char msg[80];
  225.  
  226.         (void) sprintf(msg, "[%d", Count[0]);
  227.         mlen = strlen(msg);
  228.         for (i = &Count[1]; i < &Count[10]; i++) {
  229.             if (*i == 0) {
  230.                 z++;
  231.                 continue;
  232.             }
  233.             while (--z >= 0)
  234.                 msg[mlen++] = '.', msg[mlen++] = '0';
  235.             z = 0;
  236.             (void) sprintf(msg + mlen, ".%d", *i);
  237.             mlen += strlen(msg + mlen);
  238.         }
  239.         message(1, msg, mlen);
  240.     }
  241. }
  242.  
  243. /*
  244.  * End a page (process a DVI_EOP).
  245.  */
  246. EndPage()
  247. {
  248.     if (!ExpectEOP)
  249.         GripeUnexpectedOp("EOP");
  250.     ExpectEOP = 0;
  251.     ExpectBOP++;
  252.  
  253.     if (!UseThisPage)
  254.         return;
  255.  
  256.     if (!SFlag)
  257.         message(0, "]", 1);
  258.  
  259.     putc(DVI_EOP, outf);
  260.     if (ferror(outf))
  261.         error(1, errno, writeerr);
  262.     CurrentPosition++;
  263.     NumberOfOutputPages++;
  264. }
  265.  
  266. /*
  267.  * For each of the fonts used in the new DVI file, write out a definition.
  268.  */
  269. /* ARGSUSED */
  270. PostAmbleFontEnumerator(addr, key)
  271.     char *addr;
  272.     i32 key;
  273. {
  274.  
  275.     if (((struct fontinfo *) addr)->fi_reallyused)
  276.         WriteFont((struct fontinfo *) addr);
  277. }
  278.  
  279. HandlePostAmble()
  280. {
  281.     register i32 c;
  282.  
  283.     (void) GetLong(inf);    /* previous page pointer */
  284.     if (GetLong(inf) != Numerator)
  285.         GripeMismatchedValue("numerator");
  286.     if (GetLong(inf) != Denominator)
  287.         GripeMismatchedValue("denominator");
  288.     if (GetLong(inf) != DVIMag)
  289.         GripeMismatchedValue("\\magfactor");
  290.  
  291.     putc(DVI_POST, outf);
  292.     PutLong(outf, StartOfLastPage);
  293.     PutLong(outf, Numerator);
  294.     PutLong(outf, Denominator);
  295.     PutLong(outf, DVIMag);
  296.     c = GetLong(inf);
  297.     PutLong(outf, c);    /* tallest page height */
  298.     c = GetLong(inf);
  299.     PutLong(outf, c);    /* widest page width */
  300.     c = GetWord(inf);
  301.     PutWord(outf, c);    /* DVI stack size */
  302.     PutWord(outf, NumberOfOutputPages);
  303.     StartOfLastPage = CurrentPosition;    /* point at post */
  304.     CurrentPosition += 29;    /* count all those `put's */
  305. #ifdef notdef
  306.     (void) GetWord(inf);    /* skip original number of pages */
  307. #endif
  308.  
  309.     /*
  310.      * just ignore all the incoming font definitions; we are done with
  311.      * input file 
  312.      */
  313.  
  314.     /*
  315.      * run through the FontFinder table and dump definitions for the
  316.      * fonts we have used. 
  317.      */
  318.     SEnumerate(FontFinder, PostAmbleFontEnumerator);
  319.  
  320.     putc(DVI_POSTPOST, outf);
  321.     PutLong(outf, StartOfLastPage);    /* actually start of postamble */
  322.     putc(DVI_VERSION, outf);
  323.     putc(DVI_FILLER, outf);
  324.     putc(DVI_FILLER, outf);
  325.     putc(DVI_FILLER, outf);
  326.     putc(DVI_FILLER, outf);
  327.     CurrentPosition += 10;
  328.     while (CurrentPosition & 3)
  329.         putc(DVI_FILLER, outf), CurrentPosition++;
  330.     if (ferror(outf))
  331.         error(1, errno, writeerr);
  332. }
  333.  
  334. /*
  335.  * Write a font definition to the output file
  336.  */
  337. WriteFont(fi)
  338.     register struct fontinfo *fi;
  339. {
  340.     register int l;
  341.     register char *s;
  342.  
  343.     if (fi->fi_newindex < 256) {
  344.         putc(DVI_FNTDEF1, outf);
  345.         putc(fi->fi_newindex, outf);
  346.         CurrentPosition += 2;
  347.     } else if (fi->fi_newindex < 65536) {
  348.         putc(DVI_FNTDEF2, outf);
  349.         PutWord(outf, fi->fi_newindex);
  350.         CurrentPosition += 3;
  351.     } else if (fi->fi_newindex < 16777216) {
  352.         putc(DVI_FNTDEF3, outf);
  353.         Put3Byte(outf, fi->fi_newindex);
  354.         CurrentPosition += 4;
  355.     } else {
  356.         putc(DVI_FNTDEF4, outf);
  357.         PutLong(outf, fi->fi_newindex);
  358.         CurrentPosition += 5;
  359.     }
  360.     PutLong(outf, fi->fi_checksum);
  361.     PutLong(outf, fi->fi_mag);
  362.     PutLong(outf, fi->fi_designsize);
  363.     putc(fi->fi_n1, outf);
  364.     putc(fi->fi_n2, outf);
  365.     l = fi->fi_n1 + fi->fi_n2;
  366.     CurrentPosition += 14 + l;
  367.     s = fi->fi_name;
  368.     while (--l >= 0)
  369.         putc(*s, outf), s++;
  370. }
  371.  
  372. /*
  373.  * Handle the preamble.  Someday we should update the comment field.
  374.  */
  375. HandlePreAmble()
  376. {
  377.     register int n, c;
  378.  
  379.     if (GetByte(inf) != Sign8(DVI_PRE))
  380.         GripeMissingOp("PRE");
  381.     if (GetByte(inf) != Sign8(DVI_VERSION))
  382.         GripeMismatchedValue("DVI version number");
  383.     Numerator = GetLong(inf);
  384.     Denominator = GetLong(inf);
  385.     DVIMag = GetLong(inf);
  386.     putc(DVI_PRE, outf);
  387.     putc(DVI_VERSION, outf);
  388.     PutLong(outf, Numerator);
  389.     PutLong(outf, Denominator);
  390.     PutLong(outf, DVIMag);
  391.  
  392.     n = UnSign8(GetByte(inf));
  393.     CurrentPosition = 15 + n;    /* well, almost */
  394.     putc(n, outf);
  395.     while (--n >= 0) {
  396.         c = GetByte(inf);
  397.         putc(c, outf);    /* never trust a macro, I always say */
  398.     }
  399. }
  400.  
  401. main(argc, argv)
  402.     int argc;
  403.     register char **argv;
  404. {
  405.     register int c;
  406.     register char *s;
  407.     char *inname = NULL, *outname = NULL;
  408.  
  409.     ProgName = *argv;
  410.     setbuf(stderr, serrbuf);
  411.  
  412.     while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
  413.         switch (c) {
  414.  
  415.         case 's':    /* silent */
  416.             SFlag++;
  417.             break;
  418.  
  419.         case 'i':
  420.             if (inname != NULL)
  421.                 goto usage;
  422.             inname = optarg;
  423.             break;
  424.  
  425.         case 'o':
  426.             if (outname != NULL)
  427.                 goto usage;
  428.             outname = optarg;
  429.             break;
  430.  
  431.         case '?':
  432. usage:
  433.             fprintf(stderr, "\
  434. Usage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
  435.                 ProgName);
  436.             (void) fflush(stderr);
  437.             exit(1);
  438.         }
  439.     }
  440.  
  441.     while (optind < argc) {
  442.         s = argv[optind++];
  443.         c = *s;
  444.         if (!isalpha(c) && c != '/') {
  445.             if (ParsePages(s))
  446.                 goto usage;
  447.         } else if (inname == NULL)
  448.             inname = s;
  449.         else if (outname == NULL)
  450.             outname = s;
  451.         else
  452.             goto usage;
  453.     }
  454.     if (PageList == NULL)
  455.         goto usage;
  456.     if (inname == NULL)
  457.         inf = stdin;
  458.     else if ((inf = fopen(inname, "r")) == 0)
  459.         error(1, errno, "cannot read %s", inname);
  460.     if (outname == NULL)
  461.         outf = stdout;
  462.     else if ((outf = fopen(outname, "w")) == 0)
  463.         error(1, errno, "cannot write %s", outname);
  464.  
  465.     if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
  466.         error(1, 0, "cannot create font finder (out of memory?)");
  467.  
  468.     ExpectBOP++;
  469.     StartOfLastPage = -1;
  470.     HandlePreAmble();
  471.     HandleDVIFile();
  472.     HandlePostAmble();
  473.     if (!SFlag)
  474.         fprintf(stderr, "\nWrote %d pages, %d bytes\n",
  475.             NumberOfOutputPages, CurrentPosition);
  476.     exit(0);
  477. }
  478.  
  479. struct pagelist *
  480. InstallPL(ps, n, absolute)
  481.     register struct pagesel *ps;
  482.     register int n;
  483.     int absolute;
  484. {
  485.     register struct pagelist *pl;
  486.  
  487.     pl = (struct pagelist *) malloc(sizeof *pl);
  488.     if (pl == NULL)
  489.         GripeOutOfMemory(sizeof *pl, "page list");
  490.     pl->pl_alt = PageList;
  491.     PageList = pl;
  492.     pl->pl_len = n;
  493.     while (--n >= 0)
  494.         pl->pl_pages[n] = ps[n];
  495.     pl->pl_abs = absolute;
  496. }
  497.  
  498. /*
  499.  * Parse a string representing a list of pages.  Return 0 iff ok.  As a
  500.  * side effect, the page selection(s) is (are) prepended to PageList.
  501.  */
  502. ParsePages(s)
  503.     register char *s;
  504. {
  505.     register struct pagesel *ps;
  506.     register int c;        /* current character */
  507.     register i32 n;        /* current numeric value */
  508.     register int innumber;    /* true => gathering a number */
  509.     int i;            /* next index in page select list */
  510.     int range;        /* true => saw a range indicator */
  511.     int negative;        /* true => number being built is negative */
  512.     int absolute;        /* true => absolute, not \count */
  513.     struct pagesel pagesel[10];
  514.  
  515. #define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
  516.  
  517.     range = 0;
  518.     innumber = 0;
  519.     absolute = 0;
  520.     i = 0;
  521.     ps = pagesel;
  522.     /*
  523.      * Talk about ad hoc!  (Not to mention convoluted.)
  524.      */
  525.     for (;;) {
  526.         c = *s++;
  527.         if (i == 0 && !innumber && !range) {
  528.             /* nothing special going on */
  529.             if (c == 0)
  530.                 return 0;
  531.             if (white(c))
  532.                 continue;
  533.         }
  534.         if (c == '_') {
  535.             /* kludge: should be '-' for negatives */
  536.             if (innumber || absolute)
  537.                 return (-1);
  538.             innumber++;
  539.             negative = 1;
  540.             n = 0;
  541.             continue;
  542.         }
  543.         if (c == '=') {
  544.             /* absolute page */
  545.             if (innumber || range || i > 0)
  546.                 return (-1);
  547.             absolute++;
  548.             /*
  549.              * Setting innumber means that there is always
  550.              * a lower bound, but this is all right since
  551.              * `=:4' is treated as if it were `=0:4'.  As
  552.              * there are no negative absolute page numbers,
  553.              * this selects pages 1:4, which is the proper
  554.              * action.
  555.              */
  556.             innumber++;
  557.             negative = 0;
  558.             n = 0;
  559.             continue;
  560.         }
  561.         if (isdigit(c)) {
  562.             /* accumulate numeric value */
  563.             if (!innumber) {
  564.                 innumber++;
  565.                 negative = 0;
  566.                 n = c - '0';
  567.                 continue;
  568.             }
  569.             n *= 10;
  570.             n += negative ? '0' - c : c - '0';
  571.             continue;
  572.         }
  573.         if (c == '-' || c == ':') {
  574.             /* here is a range */
  575.             if (range)
  576.                 return (-1);
  577.             if (innumber) {    /* have a lower bound */
  578.                 ps->ps_low = n;
  579.                 ps->ps_nol = 0;
  580.             } else
  581.                 ps->ps_nol = 1;
  582.             range++;
  583.             innumber = 0;
  584.             continue;
  585.         }
  586.         if (c == '*') {
  587.             /* no lower bound, no upper bound */
  588.             c = *s++;
  589.             if (innumber || range || i >= 10 ||
  590.                 (c && c != '.' && !white(c)))
  591.                 return (-1);
  592.             ps->ps_nol = 1;
  593.             ps->ps_noh = 1;
  594.             goto finishnum;
  595.         }
  596.         if (c == 0 || c == '.' || white(c)) {
  597.             /* end of this range */
  598.             if (i >= 10)
  599.                 return (-1);
  600.             if (!innumber) {    /* no upper bound */
  601.                 ps->ps_noh = 1;
  602.                 if (!range)    /* no lower bound either */
  603.                     ps->ps_nol = 1;
  604.             } else {        /* have an upper bound */
  605.                 ps->ps_high = n;
  606.                 ps->ps_noh = 0;
  607.                 if (!range) {
  608.                     /* no range => lower bound == upper */
  609.                     ps->ps_low = ps->ps_high;
  610.                     ps->ps_nol = 0;
  611.                 }
  612.             }
  613. finishnum:
  614.             i++;
  615.             if (c == '.') {
  616.                 if (absolute)
  617.                     return (-1);
  618.                 ps++;
  619.             } else {
  620.                 InstallPL(pagesel, i, absolute);
  621.                 ps = pagesel;
  622.                 i = 0;
  623.                 absolute = 0;
  624.             }
  625.             if (c == 0)
  626.                 return (0);
  627.             range = 0;
  628.             innumber = 0;
  629.             continue;
  630.         }
  631.         /* illegal character */
  632.         return (-1);
  633.     }
  634. #undef white
  635. }
  636.  
  637. /*
  638.  * Handle a font definition.
  639.  */
  640. HandleFontDef(index)
  641.     i32 index;
  642. {
  643.     register struct fontinfo *fi;
  644.     register int i;
  645.     register char *s;
  646.     int def = S_CREATE | S_EXCL;
  647.  
  648.     if ((fi = (struct fontinfo *) SSearch(FontFinder, index, &def)) == 0)
  649.         if (def & S_COLL)
  650.             error(1, 0, "font %d already defined", index);
  651.         else
  652.             error(1, 0, "cannot stash font %d (out of memory?)",
  653.                 index);
  654.     fi->fi_reallyused = 0;
  655.     fi->fi_checksum = GetLong(inf);
  656.     fi->fi_mag = GetLong(inf);
  657.     fi->fi_designsize = GetLong(inf);
  658.     fi->fi_n1 = UnSign8(GetByte(inf));
  659.     fi->fi_n2 = UnSign8(GetByte(inf));
  660.     i = fi->fi_n1 + fi->fi_n2;
  661.     if ((s = malloc((unsigned) i)) == 0)
  662.         GripeOutOfMemory(i, "font name");
  663.     fi->fi_name = s;
  664.     while (--i >= 0)
  665.         *s++ = GetByte(inf);
  666. }
  667.  
  668. /*
  669.  * Handle a \special.
  670.  */
  671. HandleSpecial(c, l, p)
  672.     int c;
  673.     register int l;
  674.     register i32 p;
  675. {
  676.     register int i;
  677.  
  678.     if (UseThisPage) {
  679.         putc(c, outf);
  680.         switch (l) {
  681.  
  682.         case DPL_UNS1:
  683.             putc(p, outf);
  684.             CurrentPosition += 2;
  685.             break;
  686.  
  687.         case DPL_UNS2:
  688.             PutWord(outf, p);
  689.             CurrentPosition += 3;
  690.             break;
  691.  
  692.         case DPL_UNS3:
  693.             Put3Byte(outf, p);
  694.             CurrentPosition += 4;
  695.             break;
  696.  
  697.         case DPL_SGN4:
  698.             PutLong(outf, p);
  699.             CurrentPosition += 5;
  700.             break;
  701.  
  702.         default:
  703.             panic("HandleSpecial l=%d", l);
  704.             /* NOTREACHED */
  705.         }
  706.         CurrentPosition += p;
  707.         while (--p >= 0) {
  708.             i = getc(inf);
  709.             putc(i, outf);
  710.         }
  711.         if (feof(inf))
  712.             error(1, 0, "unexpected EOF");
  713.         if (ferror(outf))
  714.             error(1, errno, writeerr);
  715.     } else
  716.         while (--p >= 0)
  717.             (void) getc(inf);
  718. }
  719.  
  720. ReallyUseFont()
  721. {
  722.     register struct fontinfo *fi;
  723.     int look = S_LOOKUP;
  724.  
  725.     fi = (struct fontinfo *) SSearch(FontFinder, CurrentFontIndex, &look);
  726.     if (fi == 0)
  727.         error(1, 0, "index %d not in font table!", CurrentFontIndex);
  728.     if (fi->fi_reallyused == 0) {
  729.         fi->fi_reallyused++;
  730.         fi->fi_newindex = NextOutputFontIndex++;
  731.         WriteFont(fi);
  732.     }
  733.     if (fi->fi_newindex != OutputFontIndex) {
  734.         PutFontSelector(fi->fi_newindex);
  735.         OutputFontIndex = fi->fi_newindex;
  736.     }
  737. }
  738.  
  739. /*
  740.  * Write a font selection command to the output file
  741.  */
  742. PutFontSelector(index)
  743.     i32 index;
  744. {
  745.  
  746.     if (index < 64) {
  747.         putc(index + DVI_FNTNUM0, outf);
  748.         CurrentPosition++;
  749.     } else if (index < 256) {
  750.         putc(DVI_FNT1, outf);
  751.         putc(index, outf);
  752.         CurrentPosition += 2;
  753.     } else if (index < 65536) {
  754.         putc(DVI_FNT2, outf);
  755.         PutWord(outf, index);
  756.         CurrentPosition += 3;
  757.     } else if (index < 16777216) {
  758.         putc(DVI_FNT3, outf);
  759.         Put3Byte(outf, index);
  760.         CurrentPosition += 4;
  761.     } else {
  762.         putc(DVI_FNT4, outf);
  763.         PutLong(outf, index);
  764.         CurrentPosition += 5;
  765.     }
  766. }
  767.  
  768. /*
  769.  * The following table describes the length (in bytes) of each of the DVI
  770.  * commands that we can simply copy, starting with DVI_SET1 (128).
  771.  */
  772. char    oplen[128] = {
  773.     0, 0, 0, 0,        /* DVI_SET1 .. DVI_SET4 */
  774.     9,            /* DVI_SETRULE */
  775.     0, 0, 0, 0,        /* DVI_PUT1 .. DVI_PUT4 */
  776.     9,            /* DVI_PUTRULE */
  777.     1,            /* DVI_NOP */
  778.     0,            /* DVI_BOP */
  779.     0,            /* DVI_EOP */
  780.     1,            /* DVI_PUSH */
  781.     1,            /* DVI_POP */
  782.     2, 3, 4, 5,        /* DVI_RIGHT1 .. DVI_RIGHT4 */
  783.     1,            /* DVI_W0 */
  784.     2, 3, 4, 5,        /* DVI_W1 .. DVI_W4 */
  785.     1,            /* DVI_X0 */
  786.     2, 3, 4, 5,        /* DVI_X1 .. DVI_X4 */
  787.     2, 3, 4, 5,        /* DVI_DOWN1 .. DVI_DOWN4 */
  788.     1,            /* DVI_Y0 */
  789.     2, 3, 4, 5,        /* DVI_Y1 .. DVI_Y4 */
  790.     1,            /* DVI_Z0 */
  791.     2, 3, 4, 5,        /* DVI_Z1 .. DVI_Z4 */
  792.     0,            /* DVI_FNTNUM0 (171) */
  793.     0, 0, 0, 0, 0, 0, 0, 0,    /* 172 .. 179 */
  794.     0, 0, 0, 0, 0, 0, 0, 0,    /* 180 .. 187 */
  795.     0, 0, 0, 0, 0, 0, 0, 0,    /* 188 .. 195 */
  796.     0, 0, 0, 0, 0, 0, 0, 0,    /* 196 .. 203 */
  797.     0, 0, 0, 0, 0, 0, 0, 0,    /* 204 .. 211 */
  798.     0, 0, 0, 0, 0, 0, 0, 0,    /* 212 .. 219 */
  799.     0, 0, 0, 0, 0, 0, 0, 0,    /* 220 .. 227 */
  800.     0, 0, 0, 0, 0, 0, 0,    /* 228 .. 234 */
  801.     0, 0, 0, 0,        /* DVI_FNT1 .. DVI_FNT4 */
  802.     0, 0, 0, 0,        /* DVI_XXX1 .. DVI_XXX4 */
  803.     0, 0, 0, 0,        /* DVI_FNTDEF1 .. DVI_FNTDEF4 */
  804.     0,            /* DVI_PRE */
  805.     0,            /* DVI_POST */
  806.     0,            /* DVI_POSTPOST */
  807.     0, 0, 0, 0, 0, 0,    /* 250 .. 255 */
  808. };
  809.  
  810. /*
  811.  * Here we read the input DVI file and write relevant pages to the
  812.  * output DVI file. We also keep track of font changes, handle font
  813.  * definitions, and perform some other housekeeping.
  814.  */
  815. HandleDVIFile()
  816. {
  817.     register int c, l;
  818.     register i32 p;
  819.     register int CurrentFontOK = 0;
  820.  
  821.     /* Only way out is via "return" statement */
  822.     for (;;) {
  823.         c = getc(inf);    /* getc() returns unsigned values */
  824.         if (DVI_IsChar(c)) {
  825.             /*
  826.              * Copy chars, note font usage, but ignore if
  827.              * page is not interesting.
  828.              */
  829.             if (!UseThisPage)
  830.                 continue;
  831.             if (!CurrentFontOK) {
  832.                 ReallyUseFont();
  833.                 CurrentFontOK++;
  834.             }
  835.             putc(c, outf);
  836.             CurrentPosition++;
  837.             continue;
  838.         }
  839.         if (DVI_IsFont(c)) {    /* note font change */
  840.             CurrentFontIndex = c - DVI_FNTNUM0;
  841.             CurrentFontOK = 0;
  842.             continue;
  843.         }
  844.         if ((l = (oplen - 128)[c]) != 0) {    /* simple copy */
  845.             if (!UseThisPage) {
  846.                 while (--l > 0)
  847.                     (void) getc(inf);
  848.                 continue;
  849.             }
  850.             CurrentPosition += l;
  851.             putc(c, outf);
  852.             while (--l > 0) {
  853.                 c = getc(inf);
  854.                 putc(c, outf);
  855.             }
  856.             if (ferror(outf))
  857.                 error(1, errno, writeerr);
  858.             continue;
  859.         }
  860.         if ((l = DVI_OpLen(c)) != 0) {
  861.             /*
  862.              * Handle other generics.
  863.              * N.B.: there should only be unsigned parameters
  864.              * here (save SGN4), for commands with negative
  865.              * parameters have been taken care of above.
  866.              */
  867.             switch (l) {
  868.  
  869.             case DPL_UNS1:
  870.                 p = getc(inf);
  871.                 break;
  872.  
  873.             case DPL_UNS2:
  874.                 fGetWord(inf, p);
  875.                 break;
  876.  
  877.             case DPL_UNS3:
  878.                 fGet3Byte(inf, p);
  879.                 break;
  880.  
  881.             case DPL_SGN4:
  882.                 fGetLong(inf, p);
  883.                 break;
  884.  
  885.             default:
  886.                 panic("HandleDVIFile l=%d", l);
  887.             }
  888.  
  889.             /*
  890.              * Now that we have the parameter, perform the
  891.              * command.
  892.              */
  893.             switch (DVI_DT(c)) {
  894.  
  895.             case DT_SET:
  896.             case DT_PUT:
  897.                 if (!UseThisPage)
  898.                     continue;
  899.                 if (!CurrentFontOK) {
  900.                     ReallyUseFont();
  901.                     CurrentFontOK++;
  902.                 }
  903.                 putc(c, outf);
  904.                 switch (l) {
  905.  
  906.                 case DPL_UNS1:
  907.                     putc(p, outf);
  908.                     CurrentPosition += 2;
  909.                     continue;
  910.  
  911.                 case DPL_UNS2:
  912.                     PutWord(outf, p);
  913.                     CurrentPosition += 3;
  914.                     continue;
  915.  
  916.                 case DPL_UNS3:
  917.                     Put3Byte(outf, p);
  918.                     CurrentPosition += 4;
  919.                     continue;
  920.  
  921.                 case DPL_SGN4:
  922.                     PutLong(outf, p);
  923.                     CurrentPosition += 5;
  924.                     continue;
  925.                 }
  926.  
  927.             case DT_FNT:
  928.                 CurrentFontIndex = p;
  929.                 CurrentFontOK = 0;
  930.                 continue;
  931.  
  932.             case DT_XXX:
  933.                 HandleSpecial(c, l, p);
  934.                 continue;
  935.  
  936.             case DT_FNTDEF:
  937.                 HandleFontDef(p);
  938.                 continue;
  939.  
  940.             default:
  941.                 panic("HandleDVIFile DVI_DT(%d)=%d",
  942.                       c, DVI_DT(c));
  943.             }
  944.             continue;
  945.         }
  946.  
  947.         switch (c) {    /* handle the few remaining cases */
  948.  
  949.         case DVI_BOP:
  950.             BeginPage();
  951.             CurrentFontOK = 0;
  952.             break;
  953.  
  954.         case DVI_EOP:
  955.             EndPage();
  956.             break;
  957.  
  958.         case DVI_PRE:
  959.             GripeUnexpectedOp("PRE");
  960.             /* NOTREACHED */
  961.  
  962.         case DVI_POST:
  963.             return;
  964.  
  965.         case DVI_POSTPOST:
  966.             GripeUnexpectedOp("POSTPOST");
  967.             /* NOTREACHED */
  968.  
  969.         default:
  970.             GripeUndefinedOp(c);
  971.             /* NOTREACHED */
  972.         }
  973.     }
  974. }
  975.